package export

import (
	"bytes"
	"fmt"
	"reflect"
	"strings"
	"time"

	"github.com/signintech/gopdf"
)

// GeneratePDF 生成统计报表PDF（基于gopdf库，修复所有报错）
func GeneratePDF(stats map[string]interface{}) ([]byte, string, error) {
	// 1. 初始化PDF（关键修复：gopdf.Config无TPadding等字段，用SetMargins设边距）
	pdf := gopdf.GoPdf{}
	// 正确初始化Config：仅保留PageSize（gopdf.Config实际支持的字段）
	pdf.Start(gopdf.Config{PageSize: *gopdf.PageSizeA4})
	// 单独设置边距（左15、上20、右15、下15），适配原需求
	pdf.SetMargins(15, 20, 15, 15)

	// 2. 加载中文字体（修复：AddTTFFont需正确处理路径，增加错误判断）
	fontPath := "font/simkai.ttf" // 请确保该路径下有SimKai.ttf文件
	if err := pdf.AddTTFFont("SimKai", fontPath); err != nil {
		return nil, "", fmt.Errorf("加载字体失败（请检查字体路径）：%w", err)
	}

	// 3. 绘制标题（修复：SetFont样式用"bold"而非"B"，Cell替换为Text避免参数错误）
	yPos, err := addNewPageAndResetHeader(&pdf) // 增加标题与表格间距
	if err != nil {
		return nil, "", err
	}
	contentWidth := 360.0
	col1Width := 180.0 // 适当加宽分类列
	col2Width := contentWidth - col1Width
	rowHeight := 20.0 // 适度增加行高

	// 7. 处理顶层基础数据
	for key, value := range stats {
		valKind := reflect.TypeOf(value).Kind()
		if valKind == reflect.Map || valKind == reflect.Slice {
			continue
		}
		labelStr := wrapLongText(key, 17) // 调整换行阈值
		valueStr := formatValueToString(value)

		if err := drawTableRow(&pdf, yPos, col1Width, col2Width, labelStr, valueStr); err != nil {
			return nil, "", err
		}
		yPos += rowHeight + 20

		// 分页逻辑优化（预留更多底部空间）
		if yPos > 835 {
			newY, err := addNewPageAndResetHeader(&pdf)
			if err != nil {
				return nil, "", err
			}
			yPos = newY
		}
	}

	// 8. 处理嵌套Map（增加区块间隔）
	for key, value := range stats {
		nestedMap, ok := value.(map[string]interface{})
		if !ok {
			continue
		}

		// 分页检查
		if yPos+25 > 835 {
			newY, err := addNewPageAndResetHeader(&pdf)
			if err != nil {
				return nil, "", err
			}
			yPos = newY
		}

		pdf.SetX(25)
		pdf.SetY(yPos)
		err := pdf.Text(fmt.Sprintf("当前：%s", key))
		if err != nil {
			return nil, "", err
		}
		yPos += 25 // 调整标题与表格间距
		// 绘制Map表头
		if err := drawTableHeader(&pdf, yPos, col1Width, col2Width); err != nil {
			return nil, "", err
		}
		yPos += rowHeight
		// 绘制Map数据行（使用统一行高）
		for nestedKey, nestedValue := range nestedMap {
			nestedLabel := wrapLongText(nestedKey, 17)
			nestedValStr := formatValueToString(nestedValue)
			if err := drawTableRow(&pdf, yPos, col1Width, col2Width, nestedLabel, nestedValStr); err != nil {
				return nil, "", err
			}
			yPos += rowHeight
			if yPos > 835 {
				newY, err := addNewPageAndResetHeader(&pdf)
				if err != nil {
					return nil, "", err
				}
				yPos = newY
			}
		}
		yPos += 20
	}

	// 9. 处理Slice数组（与Map保持一致调整）
	for key, value := range stats {
		sliceData, ok := value.([]interface{})
		if !ok {
			continue
		}

		if yPos+25 > 835 {
			newY, err := addNewPageAndResetHeader(&pdf)
			if err != nil {
				return nil, "", err
			}
			yPos = newY
		}
		// 绘制Slice标题
		pdf.SetX(25)
		pdf.SetY(yPos)
		err := pdf.Text(fmt.Sprintf("当前：%s", key))
		if err != nil {
			return nil, "", err
		}
		yPos += 25
		// 绘制Slice表头
		if err := drawTableHeader(&pdf, yPos, col1Width, col2Width); err != nil {
			return nil, "", err
		}
		yPos += rowHeight
		// 绘制Slice数据行
		for i, item := range sliceData {
			itemLabel := fmt.Sprintf("第%d项（索引%d）", i+1, i)
			itemValStr := formatValueToString(item)
			if err := drawTableRow(&pdf, yPos, col1Width, col2Width, itemLabel, itemValStr); err != nil {
				return nil, "", err
			}
			yPos += rowHeight
			if yPos > 835 {
				newY, err := addNewPageAndResetHeader(&pdf)
				if err != nil {
					return nil, "", err
				}
				yPos = newY
			}
		}

		yPos += 20
	}

	// 10. 生成PDF字节流（修复：WritePdf正确处理缓冲区）
	filename := fmt.Sprintf("report_statistics_%s.pdf", time.Now().Format("20060102150405"))
	var buf bytes.Buffer
	if _, err := pdf.WriteTo(&buf); err != nil {
		return nil, "", fmt.Errorf("PDF写入缓冲区失败：%w", err)
	}

	return buf.Bytes(), filename, nil
}

// formatValueToString 修复：浮点型反射逻辑，避免类型断言错误
func formatValueToString(value interface{}) string {
	switch v := value.(type) {
	case int:
		return fmt.Sprintf("%d", v)
	case int8:
		return fmt.Sprintf("%d", v)
	case int16:
		return fmt.Sprintf("%d", v)
	case int32:
		return fmt.Sprintf("%d", v)
	case int64:
		return fmt.Sprintf("%d", v)
	case uint:
		return fmt.Sprintf("%d", v)
	case uint8:
		return fmt.Sprintf("%d", v)
	case uint16:
		return fmt.Sprintf("%d", v)
	case uint32:
		return fmt.Sprintf("%d", v)
	case uint64:
		return fmt.Sprintf("%d", v)
	case float32:
		return formatFloat(float64(v))
	case float64:
		return formatFloat(v)
	case string:
		return v
	case bool:
		return fmt.Sprintf("%t", v)
	default:
		return fmt.Sprintf("%v", v)
	}
}

// formatFloat 抽离浮点型处理，避免重复代码和反射错误
func formatFloat(v float64) string {
	if v == float64(int(v)) {
		return fmt.Sprintf("%d", int(v))
	}
	return fmt.Sprintf("%.2f", v)
}

// wrapLongText 保留原逻辑，无报错
func wrapLongText(text string, maxLen int) string {
	if len(text) <= maxLen {
		return text
	}
	var result strings.Builder
	for i := 0; i < len(text); i += maxLen {
		end := i + maxLen
		if end > len(text) {
			end = len(text)
		}
		result.WriteString(text[i:end])
		if end != len(text) {
			result.WriteString("\n")
		}
	}
	return result.String()
}

// addNewPageAndResetHeader 修复：参数类型统一为float64，增加错误返回
func addNewPageAndResetHeader(pdf *gopdf.GoPdf) (float64, error) {
	pdf.AddPage()

	if err := pdf.SetFont("SimKai", "", 30); err != nil {
		return 0, fmt.Errorf("设置标题字体失败：%w", err)
	}

	title := "统计报表"
	titleWidth, _ := pdf.MeasureTextWidth(title)
	// 正确计算居中X坐标（A4宽度210mm，减去左右边距）
	titleX := (595 - titleWidth) / 2
	pdf.SetX(titleX)
	pdf.SetY(55) // 标题Y坐标（上margin后起始位置）
	err := pdf.Text(title)
	if err != nil {
		return 0, err
	}

	// 生成时间区域调整
	generateTime := time.Now().Format("生成时间：2006年01月02日 15:04:05")
	timeWidth, err := pdf.MeasureTextWidth(generateTime) // 增加错误处理
	if err != nil {
		return 0, fmt.Errorf("计算时间宽度失败：%w", err)
	}
	timeX := (595 - timeWidth) / 2
	pdf.SetX(timeX)
	pdf.SetY(90) // 微调时间位置，增加与标题间距
	err = pdf.Text(generateTime)
	if err != nil {
		return 0, err
	}

	if err := pdf.SetFont("SimKai", "", 18); err != nil {
		return 0, fmt.Errorf("设置表格字体失败：%w", err)
	}
	return 120.0, nil
}

// drawTableHeader 优化表头显示（解决高度不足和对齐问题）
func drawTableHeader(pdf *gopdf.GoPdf, y, col1Width, col2Width float64) error {
	if err := pdf.SetFont("SimKai", "", 18); err != nil {
		return fmt.Errorf("设置表头字体失败：%w", err)
	}
	// 样式优化：调整行高和对齐方式 12
	pdf.SetTextColor(0, 0, 0) // 黑色文字

	// 绘制"分类"列
	pdf.SetX(25)    // 左内边距增加到3mm
	pdf.SetY(y + 5) // 垂直居中（微调位置）
	err := pdf.Text("分类")
	if err != nil {
		return err
	}

	// 绘制"值"列
	pdf.SetX(25 + col1Width)
	pdf.SetY(y + 5)
	err = pdf.Text("值")
	if err != nil {
		return err
	}

	return nil
}

// drawTableRow 优化数据行显示（解决文字截断和边框问题）
func drawTableRow(pdf *gopdf.GoPdf, y, col1Width, col2Width float64, label, value string) error {
	if err := pdf.SetFont("SimKai", "", 18); err != nil {
		return fmt.Errorf("设置数据行字体失败：%w", err)
	}
	// 保持与表头样式统一
	pdf.SetTextColor(0, 0, 0) // 黑色文字
	// 绘制标签列单元格
	pdf.SetX(25)
	pdf.SetY(y + 5)
	err := pdf.Text(label)
	if err != nil {
		return err
	}

	// 绘制值列单元格
	pdf.SetX(25 + col1Width)
	pdf.SetY(y + 5)
	err = pdf.Text(value)
	if err != nil {
		return err
	}

	return nil
}
